package com.corticon.client.web;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.corticon.client.model.DialogReportInput;
import com.corticon.client.model.DialogReportOutput;
import com.corticon.client.model.DialogRequestInput;
import com.corticon.client.model.DialogRequestOutput;
import com.corticon.client.model.GeneralMessage;
import com.corticon.client.model.NavigatePageInput;
import com.corticon.client.model.NavigatePageOutput;
import com.corticon.client.model.ProcessResponseInput;
import com.corticon.client.model.ProcessResponseOutput;
import com.corticon.client.model.PutRuleInput;
import com.corticon.client.model.QuestionBaseOutput;
import com.corticon.client.model.ResponseEntry;
import com.corticon.client.service.CorticonApiService;
import com.corticon.client.util.ApiRequestUtil;
import com.corticon.client.validation.DialogReportValidator;
import com.corticon.client.validation.DialogRequestValidator;
import com.corticon.client.validation.NavigatePageValidator;
import com.corticon.client.validation.ProcessResponseValidator;
import com.corticon.client.validation.ValidationMessageFormatter;

import freemarker.template.TemplateException;

@Controller
public class ApiController extends BaseController {
	private final String DIALOG_REQUEST_API = "dialogRequest";
	private final String PROCESS_RESPONSE_API = "processResponse";
	private final String NAVIGATE_PAGE_API = "navigatePage";
	private final String DIALOG_REPORT_API = "dialogReport";
	private final String RENDEN_PAGE = "rendenPage";
	private final String SHOW_DIV = "showDiv";
	private ApiRequestUtil apiRequestUtil = new ApiRequestUtil();

	private DialogRequestValidator dialogRequestValidator;
	private NavigatePageValidator navigatePageValidator;
	private DialogReportValidator dialogReportValidator;
	private ProcessResponseValidator processResponseValidator;
	@Resource
	private ValidationMessageFormatter validationMessageFormatter;
	@Resource
	private CorticonApiService corticonApiService;
	private String performanceLogId="";

	/**
	 * Instantiate the validators after the construct method.
	 */
	@PostConstruct
	private void buildValidators() {
		dialogRequestValidator = new DialogRequestValidator(validationMessageFormatter);
		navigatePageValidator = new NavigatePageValidator(validationMessageFormatter);
		processResponseValidator = new ProcessResponseValidator(validationMessageFormatter);
		dialogReportValidator = new DialogReportValidator(validationMessageFormatter);
	}

	@RequestMapping(value = DIALOG_REQUEST_API)
	public String dialogRequest(@ModelAttribute("dialogRequestInput")
	DialogRequestInput dialogRequestInput, Errors errors, ModelMap model, HttpServletRequest request, HttpServletResponse response) throws IllegalArgumentException, NoSuchMethodException,
			IllegalAccessException, InvocationTargetException, Throwable {
		// Get Parameter && Translate DialogRequestInput Object
		dialogRequestInput = apiRequestUtil.getDialogReqParameter(request);
		String preview="";
		if (request.getParameter("preview") != null) {
			preview = request.getParameter("preview");
		}
		// Validate DialogRequestInput Object
		Map<String, List<String>> errorsMessages = dialogRequestValidator.invokeValidate(dialogRequestInput, errors, request.getLocale());
		if (errors.hasErrors()) {
			DialogRequestOutput dialogRequestOutput = new DialogRequestOutput();
			dialogRequestOutput.setErrorFlag(true);
			List<GeneralMessage> messages = new ArrayList();
			List<FieldError> allErrors = errors.getAllErrors();
			for (int i = 0; i < allErrors.size(); i++) {
				FieldError error = allErrors.get(i);
				GeneralMessage errorMessage = new GeneralMessage();
				errorMessage.setCode(validationMessageFormatter.getFieldErrorMessage(errors, error.getField()));
				messages.add(errorMessage);
			}
			dialogRequestOutput.setErrorMessage(messages);
			outPutJson(dialogRequestOutput.toJson().toString(), response);
			if (!preview.equals("")){
				return rendenPage(request);
			}
			return null;
		}
		String jsonObj = corticonApiService.postServerUrl(dialogRequestInput, new CorticonApiService().getDialogRequest());
		System.out.println(jsonObj);
		// Get Response Object.
		DialogRequestOutput dialogRequestOutput = new DialogRequestOutput();
		dialogRequestOutput = dialogRequestOutput.toBean(jsonObj);
		// Covert Message from i18n Source
		List<GeneralMessage> messages = checkMessage(dialogRequestOutput.getErrorMessage());
		dialogRequestOutput.setErrorMessage(messages);
		// Check Error
		if (Boolean.FALSE.equals(dialogRequestOutput.getErrorFlag())) {
			request.getSession().removeAttribute("mode");
			request.getSession().setAttribute("mode", dialogRequestOutput);
		}
		if (!preview.equals("")){
			request.setAttribute("rendenObj", "dialogRequest");
			return rendenPage(request);
		}
		Collections.sort(dialogRequestOutput.getQuestion());
		outPutJson(dialogRequestOutput.toJson().toString(), response);		
		return null;
	}

	@RequestMapping(value = RENDEN_PAGE)
	public String rendenPage(HttpServletRequest request) {
		String rendenObj = request.getParameter("rendenObj")==null?"":request.getParameter("rendenObj").toString();
		if (rendenObj.equals("")){
			rendenObj = request.getAttribute("rendenObj")==null?"":request.getAttribute("rendenObj").toString();
		}		
		if (rendenObj.equals("dialogRequest") || rendenObj.equals("navigatePage")) {
			request.getSession().getAttribute("mode");
		}

		return "api.rendenPage";
	}

	@RequestMapping(value = NAVIGATE_PAGE_API, method = RequestMethod.POST)
	public String navigatePage(@ModelAttribute("navigatePageInput")
	NavigatePageInput navigatePageInput, Errors errors, ModelMap model, HttpServletRequest request, HttpServletResponse response) throws IllegalArgumentException, IOException, NoSuchMethodException,
			IllegalAccessException, InvocationTargetException, Throwable {		
		// Get Parameter && Translate NavigatePageInput Object
		navigatePageInput = apiRequestUtil.getNavigatePageParameter(request);
		String pageName="";
		if (request.getParameter("pageName") != null) {
			pageName = request.getParameter("pageName");
		}
		performancelogger.debug("["+pageName+"][T1][beginning]");
		// Validate NavigatePageInput Object
		Map<String, List<String>> errorsMessages = navigatePageValidator.invokeValidate(navigatePageInput, errors, request.getLocale());
		if (errors.hasErrors()) {
			NavigatePageOutput navigatePageOutput = new NavigatePageOutput();
			navigatePageOutput.setErrorFlag(true);
			List<GeneralMessage> messages = new ArrayList();
			List<FieldError> allErrors = errors.getAllErrors();
			for (int i = 0; i < allErrors.size(); i++) {
				FieldError error = allErrors.get(i);
				GeneralMessage errorMessage = new GeneralMessage();
				errorMessage.setCode(validationMessageFormatter.getFieldErrorMessage(errors, error.getField()));
				messages.add(errorMessage);
			}
			navigatePageOutput.setErrorMessage(messages);
			outPutJson(navigatePageOutput.toJson().toString(), response);
			return null;
		}
		// Validate NavigatePageInput Object
		String jsonObj = corticonApiService.postServerUrl(navigatePageInput, new CorticonApiService().getNavigatePage());
		System.out.println(jsonObj);
		// Get Response Object.
		NavigatePageOutput navigatePageOutput = new NavigatePageOutput();
		navigatePageOutput = navigatePageOutput.toBean(jsonObj);
		// Check First or Last page
		List<GeneralMessage> checkMessages = navigatePageOutput.getErrorMessage();
		Boolean FirstOrLastPage = false;
		for (int i = 0; i < checkMessages.size(); i++) {
			GeneralMessage msg = checkMessages.get(i);
			if (FirstOrLastPage == false && msg.getCode() != null && msg.getCode().equals("E00060")) {
				FirstOrLastPage = true;
			}
		}

		// Covert Message from i18n Source
		if (Boolean.FALSE.equals(FirstOrLastPage)) {
			List<GeneralMessage> messages = checkMessage(navigatePageOutput.getErrorMessage());
			navigatePageOutput.setErrorMessage(messages);
		}
		Collections.sort(navigatePageOutput.getQuestion());
		// Check Error
		if (Boolean.FALSE.equals(navigatePageOutput.getErrorFlag())) {
			request.getSession().removeAttribute("mode");
			request.getSession().setAttribute("mode", navigatePageOutput);
		}
		if (Boolean.FALSE.equals(FirstOrLastPage)) {
			outPutJson(navigatePageOutput.toJson().toString(), response);
		} else {
			outPutJson("[null]", response);
		}
		// Prev && Next
		performancelogger.debug("["+pageName+"][T1][end]");
		return null;
	}

	@RequestMapping(value = PROCESS_RESPONSE_API)
	public String processResponse(@ModelAttribute("processResponseInput")
	ProcessResponseInput processResponseInput, Errors errors, ModelMap model, HttpServletRequest request, HttpServletResponse response) throws IllegalArgumentException, NoSuchMethodException,
			IllegalAccessException, InvocationTargetException, Throwable {
		// Get Parameter && Translate PutRuleInput Object
		processResponseInput = apiRequestUtil.getProcessResponseInput(request);	
		String lastQuestionName="";
		if (request.getParameter("lastQuestionName") != null) {
			lastQuestionName = request.getParameter("lastQuestionName");
		}
		performancelogger.debug("["+lastQuestionName+"][T1][beginning]");
		String postStr = processResponseInput.getQuestionData();
		String jsonObj = corticonApiService.postProcessResponseUrl(processResponseInput.getQuestionData(), new CorticonApiService().getProcessResponse(),lastQuestionName);
		System.out.println(jsonObj);
		// Get Response Object.
		ProcessResponseOutput processResponseOutput = new ProcessResponseOutput();
		processResponseOutput = processResponseOutput.toBean(jsonObj);
		// Covert Message from i18n Source
		List<GeneralMessage> messages = checkMessage(processResponseOutput.getErrorMessage());
		processResponseOutput.setErrorMessage(messages);
		// Check Error		
		outPutJson(processResponseOutput.toJson().toString(), response);
		performancelogger.debug("["+lastQuestionName+"][T1][end]");
		return null;
	}

	@RequestMapping(value = SHOW_DIV)
	public String showDiv(HttpServletRequest request, HttpServletResponse response) throws JSONException {
		String showQuestion = request.getParameterValues("paramJson")[0];
		String dialogId = request.getParameterValues("dialogId")[0];
		String pageId = request.getParameterValues("pageId")[0];
		String dialogInstanceId = request.getParameter("dialogInstanceId");
		QuestionBaseOutput q = new QuestionBaseOutput();
		JSONObject question = new JSONObject(showQuestion);
		q.setText(question.getString("text").replaceAll("  ", "\r\n").replaceAll("\'", "'"));
		q.setHelpText(question.getString("helpText"));
		q.setQuestionId(question.getInt("questionId"));
		q.setName(question.getString("name"));
		String seq = question.getString("sequence");
		String pageInQuestionId = question.getString("questionPageId");
		String uiType = "";
		String responseType = question.getString("responseType");
		String uiControlCode = question.getString("uiControl");
		String answerValue = "";
		if (responseType != null && responseType.equals("Display")) {
			uiType = responseType;
		} else {
			if (!uiControlCode.equals("") && !uiControlCode.equals("null") && (responseType.equals("Custom") || responseType.equals("Dynamic"))) {
				uiType = uiControlCode;
			} else {
				uiType = responseType;
			}
		}

		List<ResponseEntry> responses2 = new ArrayList();
		List<ResponseEntry> responses = new ArrayList();
		JSONArray rs = question.getJSONArray("responseEntry");
		for (int i = 0; i < rs.length(); i++) {
			if (!rs.isNull(i)) {
				JSONObject responseJSON = rs.getJSONObject(i);
				ResponseEntry r = new ResponseEntry();
				r.setId(responseJSON.getString("responseEntryId"));
				r.setLabel(responseJSON.getString("label").replaceAll("\'", "'"));
				r.setValue(responseJSON.getString("value"));
				r.setSequence(responseJSON.getLong("sequence"));
				if (uiType.equalsIgnoreCase("Display")) {
					// Set Response Value
					answerValue = responseJSON.getString("value");
				}
				responses2.add(r);
			}
		}

		if (uiType.equalsIgnoreCase("Radio Button") || uiType.equalsIgnoreCase("Check Box") || uiType.equalsIgnoreCase("Dropdown")) {
			Collections.sort(responses2);
		}
		request.setAttribute("answerValue", answerValue);
		request.setAttribute("uiType", uiType);
		request.setAttribute("dialogInstanceId", dialogInstanceId);
		request.setAttribute("qnId", dialogId);
		request.setAttribute("pageId", pageId);
		request.setAttribute("responses", responses2);
		request.setAttribute("question", q);
		request.setAttribute("seq", seq);
		request.setAttribute("dynamicFlag", responseType);
		request.setAttribute("pageInQuestionId", pageInQuestionId);
		return getViewNameByRequestURI(request);
	}

	@RequestMapping(value = DIALOG_REPORT_API)
	public String dialogReport(@ModelAttribute("dialogReportInput")
	DialogReportInput dialogReportInput, Errors errors, ModelMap model, HttpServletRequest request, HttpServletResponse response) throws IllegalArgumentException, NoSuchMethodException,
			IllegalAccessException, InvocationTargetException, Throwable {
		// Get Parameter && Translate NavigatePageInput Object
		dialogReportInput = apiRequestUtil.getDialogReportParameter(request);
		// Validate NavigatePageInput Object
        Map<String, List<String>> errorsMessages = dialogReportValidator.invokeValidate(dialogReportInput,errors,request.getLocale());
		if (errors.hasErrors()) {
            DialogReportOutput dialogReportOutput=new DialogReportOutput();
            dialogReportOutput.setErrorFlag(true);
			List<GeneralMessage> messages = new ArrayList();
			List<FieldError> allErrors = errors.getAllErrors();
			for (int i = 0; i < allErrors.size(); i++) {
				FieldError error = allErrors.get(i);
				GeneralMessage errorMessage = new GeneralMessage();
				errorMessage.setCode(validationMessageFormatter.getFieldErrorMessage(errors, error.getField()));
				messages.add(errorMessage);
			}
			dialogReportOutput.setErrorMessage(messages);
			outPutJson(dialogReportOutput.toJson().toString(), response);
			return null;
		}
        
		String jsonObj = corticonApiService.postServerUrl(dialogReportInput, new CorticonApiService().getDialogReport());		
		// Get Response Object.
		DialogReportOutput dialogReportOutput = new DialogReportOutput();
		dialogReportOutput = dialogReportOutput.toBean(jsonObj);
		if (dialogReportOutput.getDialogInstanceId()==null || dialogReportOutput.getDialogInstanceId().intValue()==0){
        	return null;
        }
		//Check value and label
		// Covert Message from i18n Source
		List<GeneralMessage> messages = checkMessage(dialogReportOutput.getErrorMessage());
		dialogReportOutput.setErrorMessage(messages);		
		// Check Error
		if (Boolean.FALSE.equals(dialogReportOutput.getErrorFlag())) {
			request.getSession().removeAttribute("dialogReportOutput");
			request.getSession().setAttribute("dialogReportOutput", dialogReportOutput);
		}		
        request.setAttribute("mode",dialogReportOutput);        
		return "api.dialogReport";      

	}
	
}